package com.credithc.signature.facade.configure.rabbitmq;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * 描述：rabbitmq配置<br/>
 * 作者：sunyang
 * 创建：2019/5/27 15:35
 * 版本：v1.0.0<br/>
 */
@Slf4j
@Configuration
@Data
public class FacadeRabbitConfig {

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value("${spring.rabbitmq.virtual-host:/}")
    private String virtualHost;

    @Value("${spring.rabbitmq.customConfig.exchangeName:signature-core-exchange}")
    private String exchangeName;

    @Value("${spring.rabbitmq.customConfig.queueName:signature-core-queue}")
    private String queueName;

    @Value("${spring.rabbitmq.customConfig.vipExchangeName:signature-core-exchange-vip}")
    private String vipExchangeName;

    @Value("${spring.rabbitmq.customConfig.vipQueueName:signature-core-queue-vip-1}")
    private String vip1QueueName;

    @Value("${spring.rabbitmq.customConfig.vip2QueueName:signature-core-queue-vip-2}")
    private String vip2QueueName;

    @Value("${spring.rabbitmq.customConfig.vip3QueueName:signature-core-queue-vip-3}")
    private String vip3QueueName;

    @Value("${spring.rabbitmq.customConfig.vip4QueueName:signature-core-queue-vip-4}")
    private String vip4QueueName;

    @Value("${spring.rabbitmq.customConfig.vip5QueueName:signature-core-queue-vip-5}")
    private String vip5QueueName;

    @Value("${spring.rabbitmq.customConfig.customConfig:100000}")
    private long sendTimeOut;

    @Value("${spring.rabbitmq.publisher-confirms:true}")
    private boolean publisherConfirms;

    @Value("${spring.rabbitmq.publisher-returns:true}")
    private boolean publisherReturns;

    @Value("${spring.rabbitmq.cache.connection.size:30}")
    private int connectionCacheSize;

    @Value("${spring.rabbitmq.cache.channel.size:25}")
    private int channelCacheSize;

    @Value("${spring.rabbitmq.template.retry.max-attempts:3}")
    private int maxAttempts;

    public static final String RABBITTEMPLATE_NAME = "rabbitTemplate";

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        connectionFactory.setPublisherConfirms(publisherConfirms);
        connectionFactory.setPublisherReturns(publisherReturns);
        connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CONNECTION);
        connectionFactory.setChannelCacheSize(channelCacheSize);
        connectionFactory.setConnectionCacheSize(connectionCacheSize);
        connectionFactory.setConnectionLimit(connectionCacheSize);
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }


    @Bean
    public Queue queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(queueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public DirectExchange exchange(RabbitAdmin rabbitAdmin) {
        DirectExchange directExchange = new DirectExchange(exchangeName, true, false);
        rabbitAdmin.declareExchange(directExchange);
        return directExchange;
    }


    @Bean
    public Binding Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(exchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public Queue vip1Queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(vip1QueueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public Queue vip2Queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(vip2QueueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public Queue vip3Queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(vip3QueueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public Queue vip4Queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(vip4QueueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public Queue vip5Queue(RabbitAdmin rabbitAdmin) {
        Queue queue = new Queue(vip5QueueName, true, false, false);
        rabbitAdmin.declareQueue(queue);
        return queue;
    }

    @Bean
    public DirectExchange vipExchange(RabbitAdmin rabbitAdmin) {
        DirectExchange directExchange = new DirectExchange(vipExchangeName, true, false);
        rabbitAdmin.declareExchange(directExchange);
        return directExchange;
    }


    @Bean
    public Binding vip1Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = vip1Queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(vipExchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public Binding vip2Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = vip2Queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(vipExchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public Binding vip3Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = vip3Queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(vipExchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public Binding vip4Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = vip4Queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(vipExchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public Binding vip5Binding(RabbitAdmin rabbitAdmin) {
        Queue queue = vip5Queue(rabbitAdmin);
        Binding binding = BindingBuilder.bind(queue).to(vipExchange(rabbitAdmin)).with(queue.getName());
        rabbitAdmin.declareBinding(binding);
        return binding;
    }

    @Bean
    public MessageConverter jsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 通讯问题导致发送失败的重发模板
     * @return
     */
    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(maxAttempts);
        retryTemplate.setRetryPolicy(simpleRetryPolicy);
        return retryTemplate;
    }

    @Bean(name = RABBITTEMPLATE_NAME)
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter
            ,RetryTemplate retryTemplate) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMandatory(true);
        template.setMessageConverter(messageConverter);
        template.setRetryTemplate(retryTemplate);
        return template;
    }
}
